home *** CD-ROM | disk | FTP | other *** search
/ BMUG Revelations / BMUG Revelations.toast / Utilities / Text and Speech / BBEdit 2.2.2 / BBEdit Extensions / Sources / 827.c < prev    next >
C/C++ Source or Header  |  1992-10-19  |  20KB  |  605 lines

  1. /*
  2.  * 827.c
  3.  *
  4.  * By Jamie McCarthy, Sept 92.  This is public domain.
  5.  * If you have any questions or comments, you can reach
  6.  * me at "k044477@kzoo.edu" on the Internet, or at
  7.  * "j.mccarthy" on AppleLink.
  8.  *
  9.  * This code module isn't terribly exciting, but it does
  10.  * provide a little more sample code, including doing
  11.  * a callback from assembly language (whoopee!).
  12.  *
  13.  * I take responsibility for the messy code, but the
  14.  * ugly symbol names with underscores in them were
  15.  * Rich's idea.  ;-)
  16.  *
  17.  */
  18.  
  19.  
  20.  
  21. /******************************/
  22.  
  23. #include <SetupA4.h>
  24. #include "ExternalInterface.h"
  25. #include "DialogUtilities.h"
  26.  
  27. /******************************/
  28.  
  29.     /*
  30.      * The DITL item numbers for the various controls.
  31.      */
  32.  
  33. enum {
  34.     k_essetToB = 3,
  35.     k_essetToSS,
  36.     
  37.     k_euroquotesToQuotes,
  38.     k_euroquotesToInequalities,
  39.     
  40.     k_bulletToStar,
  41.     k_bulletToO,
  42.     
  43.     k_convertSelection,
  44.     k_convertDocument,
  45.     
  46.     k_changeInPlace,
  47.     k_copyToClipboard,
  48.     
  49.     k_line
  50. } ;
  51.  
  52. /******************************/
  53.  
  54.     /*
  55.      * The preferences.
  56.      */
  57. static struct
  58. {
  59.     Boolean essetToSS;
  60.     Boolean euroquotesToInequalities;
  61.     Boolean bulletToO;
  62.     Boolean convertDocument;
  63.     Boolean copyToClipboard;
  64. } options8To7;    
  65.  
  66.     /*
  67.      * Was something selected when we started?
  68.      */
  69. static Boolean nonEmptySelection;
  70.  
  71.     /*
  72.      * These strings are only for chars with their hi bit set.  Mask off
  73.      * the hi bit, index into this array, and you have a _backwards_ C
  74.      * string, max length 4, for what to replace.  (They've got a max
  75.      * length of 4 because they have to all be the same length, and you
  76.      * can't have initialized strings in code segments, only char
  77.      * constants.  See the ThC5 User Manual, p. 496.  And they're backwards
  78.      * because the algorithm's fastest that way.  :-)  For length-4
  79.      * strings, just put them in the char constant.  For shorter strings,
  80.      * stick a terminating null on the end and put whatever you like in
  81.      * any of the remaining bytes.  Note that if you write, say, 'a\0',
  82.      * it will be interpreted as a 16-bit integer, and will be stored as
  83.      * if you'd written '\0\0a\0', which is not what you want.
  84.      *
  85.      * Do not substitute a length-0 string for any char.  The algorithm
  86.      * doesn't support this.  Sorry.  Email me with a good reason for
  87.      * mapping a character to nothing and I'll think about changing it.
  88.      */
  89. static unsigned long replacement[128] = {
  90. /*    0x00        0x01        0x02        0x03        0x04        0x05        0x06        0x07 */
  91. /*    0x08        0x09        0x0A        0x0B        0x0C        0x0D        0x0E        0x0F */
  92.     'eA\0x', 'A\0xx', 'C\0xx', 'E\0xx', 'N\0xx', 'eO\0x', 'eU\0x', 'a\0xx',  // 0x80
  93.     'a\0xx', 'a\0xx', 'ea\0x', 'a\0xx', 'a\0xx', 'c\0xx', 'e\0xx', 'e\0xx',  // 0x88
  94.     'e\0xx', 'e\0xx', 'i\0xx', 'i\0xx', 'i\0xx', 'i\0xx', 'n\0xx', 'o\0xx',  // 0x90
  95.     'o\0xx', 'o\0xx', 'eo\0x', 'o\0xx', 'u\0xx', 'u\0xx', 'u\0xx', 'eu\0x',  // 0x98
  96.     '*\0xx', '*\0xx', 'c\0xx', '#\0xx', 'S\0xx', 'xxx\0', 'P\0xx', 'xxx\0',  // 0xA0
  97.     ')R(\0', ')c(\0', ')MT(',  '\'\0xx',' \0xx', '><\0x', 'EA\0x', 'O\0xx',  // 0xA8
  98.     ')()(',  '-/+\0', '=<\0x', '=>\0x', 'neY\0', 'u\0xx', 'd\0xx', 'muS\0',  // 0xB0
  99.     'IP\0x', 'ip\0x', 'tnI\0', 'a\0xx', 'o\0xx', 'mhO\0', 'ea\0x', 'o\0xx',  // 0xB8
  100.     '?\0xx', '!\0xx', '-\0xx', '/\0xx', 'f\0xx', '=\0xx', 'D\0xx', 'xxx\0',  // 0xC0
  101.     'xxx\0', '...\0', ' \0xx', 'A\0xx', 'A\0xx', 'O\0xx', 'EO\0x', 'eo\0x',  // 0xC8
  102.     '-\0xx', '--\0x', '"\0xx', '"\0xx', '\'\0xx','\'\0xx','/\0xx', 'o\0xx',  // 0xD0
  103.     'ey\0x', 'eY\0x', '/\0xx', 'O\0xx', '<\0xx', '>\0xx', 'if\0x', 'lf\0x',  // 0xD8
  104.     '*\0xx', '.\0xx', ',\0xx', ',\0xx', '00/0',  'A\0xx', 'E\0xx', 'A\0xx',  // 0xE0
  105.     'eE\0x', 'E\0xx', 'I\0xx', 'I\0xx', 'I\0xx', 'I\0xx', 'O\0xx', 'O\0xx',  // 0xE8
  106.     '*\0xx', 'O\0xx', 'U\0xx', 'U\0xx', 'U\0xx', 'i\0xx', '^\0xx', '~\0xx',  // 0xF0
  107.     '\'\0xx','\'\0xx','\'\0xx','*\0xx', ',\0xx', '"\0xx', ',\0xx', '\'\0xx'  // 0xF8
  108. } ;
  109.  
  110.     /*
  111.      * This array counts how much longer the replacement is than
  112.      * what's it's replacing.
  113.      */
  114. static char repExtraLength[256] = {
  115.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  116.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  117.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  118.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  119.     
  120.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  121.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  122.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  123.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
  124.     
  125.     1, 0, 0, 0, 0, 1, 1, 0,   0, 0, 1, 0, 0, 0, 0, 0,
  126.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 1, 0, 0, 0, 0, 1,
  127.     0, 0, 0, 0, 0, 0, 0, 0,   2, 2, 3, 0, 0, 1, 1, 0,
  128.     3, 2, 1, 1, 2, 0, 0, 2,   1, 1, 2, 0, 0, 2, 1, 0,
  129.     
  130.     0, 0, 0, 0, 0, 0, 0, 0,   0, 2, 0, 0, 0, 0, 1, 1,
  131.     0, 1, 0, 0, 0, 0, 0, 0,   1, 1, 0, 0, 0, 0, 1, 1,
  132.     0, 0, 0, 0, 3, 0, 0, 0,   1, 0, 0, 0, 0, 0, 0, 0,
  133.     0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0
  134. } ;
  135.  
  136. /******************************/
  137.  
  138.     /*
  139.      * How often should the progress thermometer be updated?
  140.      */
  141.  
  142. #define nPrgsBytes (16384L)
  143.  
  144. /******************************/
  145.  
  146. void maintain_buttons(DialogPtr d);
  147.  
  148. void updateReplacementArray(void);
  149.  
  150. long resizeTextHndl(ExternalCallbackBlock *callbacks,
  151.     Handle text, long offset, long changeStart, long changeEnd,
  152.     long *selStart, long *selEnd);
  153. void replaceText(ExternalCallbackBlock *callbacks,
  154.     Handle text, long offset, long changeStart, long changeEnd,
  155.     long textLen, long lengthIncrease);
  156.  
  157. pascal void main(ExternalCallbackBlock *callbacks, WindowPtr w);
  158.  
  159. /******************************/
  160.  
  161.  
  162.  
  163. void maintain_buttons(DialogPtr d)
  164. {
  165.     if (!nonEmptySelection) {
  166.         XAbleDlgCtl(d, k_convertSelection, FALSE);
  167.         options8To7.convertDocument = TRUE;
  168.     }
  169.     SetDlgCtl(d, k_essetToB,                        !options8To7.essetToSS);
  170.     SetDlgCtl(d, k_essetToSS,                         options8To7.essetToSS);
  171.     SetDlgCtl(d, k_bulletToStar,                    !options8To7.bulletToO);
  172.     SetDlgCtl(d, k_bulletToO,                         options8To7.bulletToO);
  173.     SetDlgCtl(d, k_euroquotesToQuotes,            !options8To7.euroquotesToInequalities);
  174.     SetDlgCtl(d, k_euroquotesToInequalities,     options8To7.euroquotesToInequalities);
  175.     SetDlgCtl(d, k_convertSelection,                !options8To7.convertDocument);
  176.     SetDlgCtl(d, k_convertDocument,                 options8To7.convertDocument);
  177.     SetDlgCtl(d, k_changeInPlace,                    !options8To7.copyToClipboard);
  178.     SetDlgCtl(d, k_copyToClipboard,                 options8To7.copyToClipboard);
  179. }
  180.  
  181.  
  182.  
  183. void updateReplacementArray(void)
  184. {
  185.         /*
  186.          * Apparently, there's this nasty restriction about assigning
  187.          * to global arrays in a code segment.  I'm not sure why that is,
  188.          * and I don't know if I'm gonna break something by doing this.
  189.          *
  190.          * But hey, let's fool the compiler.  It's fun and easy!  We'll
  191.          * take the address where we'd like to stuff a value, cast its
  192.          * type to a regular old (unsigned long *), and happily write
  193.          * to that location.
  194.          */
  195.     
  196.     if (options8To7.essetToSS) {
  197.         *(unsigned long*)(&replacement[0x00A7 - 128]) = 'ss\0\0';
  198.         *(char *)(&repExtraLength[0x00A7]) = 1;
  199.     } else {
  200.         *(unsigned long*)(&replacement[0x00A7 - 128]) = 'B\0\0\0';
  201.         *(char *)(&repExtraLength[0x00A7]) = 0;
  202.     }
  203.     
  204.     if (options8To7.euroquotesToInequalities) {
  205.         *(unsigned long*)(&replacement[0x00C7 - 128]) = '<<\0\0';
  206.         *(unsigned long*)(&replacement[0x00C8 - 128]) = '>>\0\0';
  207.         *(char *)(&repExtraLength[0x00C7]) = 1;
  208.         *(char *)(&repExtraLength[0x00C8]) = 1;
  209.     } else {
  210.         *(unsigned long*)(&replacement[0x00C7 - 128]) = '"\0\0\0';
  211.         *(unsigned long*)(&replacement[0x00C8 - 128]) = '"\0\0\0';
  212.         *(char *)(&repExtraLength[0x00C7]) = 0;
  213.         *(char *)(&repExtraLength[0x00C8]) = 0;
  214.     }
  215.     
  216.     if (options8To7.bulletToO) {
  217.         *(unsigned long*)(&replacement[0x00A5 - 128]) = 'o\0\0\0';
  218.         *(char *)(&repExtraLength[0x00A5]) = 0;
  219.     } else {
  220.         *(unsigned long*)(&replacement[0x00A5 - 128]) = '*\0\0\0';
  221.         *(char *)(&repExtraLength[0x00A5]) = 0;
  222.     }
  223. }
  224.  
  225.  
  226.  
  227. /******************************/
  228.  
  229.  
  230.  
  231.     /*
  232.      * In these routines, the serious ones where work actually gets done,
  233.      * we want to call the DoProgress() callback.  It's nice to give
  234.      * feedback, just in case this is going to take a long time.  (If
  235.      * you haven't seen the progress-o-meter, try converting a lot of
  236.      * text:  less than about two megs, and the dialog doesn't even
  237.      * show up on my IIci.)
  238.      *
  239.      * But we don't want to call DoProgress() after processing each
  240.      * character;  we'd spend lots more time doing that than actually
  241.      * doing any work.  But neither would it make sense to call the
  242.      * callback after the loop was over, eh?  So we strike a compromise:
  243.      * we decide on a certain number of bytes, and only call
  244.      * DoProgress() every time we reach that number of bytes.  (It's
  245.      * predefined as 16K.)
  246.      *
  247.      * One way of doing this would be to loop the pointer until it
  248.      * reaches its destination, and meanwhile increment a counter
  249.      * until it reached the value that means "call DoProgress()."
  250.      * But that's a little wasteful;  there's no sense keeping track
  251.      * of two counters when one will do.  So, both resizeTextHndl()
  252.      * and replaceText() use a slightly more efficient approach.
  253.      *
  254.      * They set a "check pointer" to the initial pointer, and add in
  255.      * that 16K.  Then, they make sure it's not past the _end_ of
  256.      * where they're supposed to be going.  If it is, they set it to
  257.      * the end.  Then they do the loop, and the only test that's made
  258.      * is against the check pointer.  When the index pointer equals
  259.      * the check pointer, if it's equal to the end pointer, we're
  260.      * done!  If not, call DoProgress(), add another 16K to the check
  261.      * pointer, make sure it's not past the end pointer, and keep
  262.      * looping.  (The flow isn't _exactly_ the same in the assembler
  263.      * and C versions, but they both do the same thing.)
  264.      */
  265.     
  266. long resizeTextHndl(ExternalCallbackBlock *callbacks,
  267.     Handle text, long offset, long changeStart, long changeEnd,
  268.     long *selStart, long *selEnd)
  269.         /*
  270.          * Walk through the text, figuring out how many chars we'll
  271.          * need to extend the length by.  Then resize the handle,
  272.          * and return the number of chars that it was extended.
  273.          */
  274. {
  275.     long oldLength;
  276.     register long extraLength;
  277.     register char nExtraChars;
  278.     long actualLength;
  279.     register unsigned char *srcP;
  280.     register unsigned char *checkP;
  281.     unsigned char *selStartP, *selEndP, *changeEndP;
  282.     
  283.     oldLength = GetHandleSize(text);
  284.     
  285.     srcP = (unsigned char *) *text - offset + changeStart;
  286.     selStartP = (unsigned char *) *text - offset + *selStart;
  287.     selEndP = (unsigned char *) *text - offset + *selEnd;
  288.     changeEndP = (unsigned char *) *text - offset + changeEnd;
  289.     extraLength = 0;
  290.     checkP = srcP + nPrgsBytes;
  291.     if (checkP > selStartP) checkP = selStartP;
  292.     
  293.         /*
  294.          * Walk through up to the start of the selection.  While we're
  295.          * walking here, selStart and selEnd get increased for each
  296.          * extra char we'll be adding.
  297.          */
  298.     while (srcP < selStartP) {
  299.         while (srcP < checkP) {
  300.             nExtraChars = repExtraLength[*srcP++];
  301.             extraLength += nExtraChars;
  302.             if (nExtraChars > 0) {
  303.                 *selStart += nExtraChars;
  304.                 *selEnd += nExtraChars;
  305.             }
  306.         }
  307.             /*
  308.              * Assume this routine takes half the total time, and that
  309.              * replaceText() takes the other half.
  310.              */
  311.         callbacks->DoProgress( (srcP - ((unsigned char*) *text - offset + changeStart)) / 2 );
  312.         checkP += nPrgsBytes;
  313.         if (checkP > selStartP) checkP = selStartP;
  314.     }
  315.     
  316.         /*
  317.          * Walk through, between the start and the end of the selection.
  318.          * While walking here, only selEnd gets bumped up.
  319.          */
  320.     while (srcP < selEndP) {
  321.         while (srcP < checkP) {
  322.             nExtraChars = repExtraLength[*srcP++];
  323.             extraLength += nExtraChars;
  324.             if (nExtraChars > 0) {
  325.                 *selEnd += nExtraChars;
  326.             }
  327.         }
  328.         callbacks->DoProgress( (srcP - ((unsigned char*) *text - offset + changeStart)) / 2 );
  329.         checkP += nPrgsBytes;
  330.         if (checkP > selEndP) checkP = selEndP;
  331.     }
  332.     
  333.         /*
  334.          * Walk after the selection.  In this part of the document,
  335.          * neither selStart nor selEnd need be pushed back.
  336.          */
  337.     while (srcP < changeEndP) {
  338.         while (srcP < checkP) {
  339.             extraLength += repExtraLength[*srcP++];
  340.         }
  341.         callbacks->DoProgress( (srcP - ((unsigned char*) *text - offset + changeStart)) / 2 );
  342.         checkP += nPrgsBytes;
  343.         if (checkP > changeEndP) checkP = changeEndP;
  344.     }
  345.     
  346.     SetHandleSize(text, oldLength + extraLength);
  347.     
  348.     actualLength = GetHandleSize(text);
  349.     if (actualLength != oldLength + extraLength) return -1;
  350.     else return extraLength;
  351. }
  352.  
  353.  
  354.  
  355. void replaceText(ExternalCallbackBlock *callbacks,
  356.     Handle text, long offset, long changeStart, long changeEnd,
  357.     long textLen, long lengthIncrease)
  358.         /*
  359.          * The main loop:  run through and replace everything between
  360.          * changeStart and changeEnd.  Since the new text will be either
  361.          * the same size or longer, we start at the _end_ and run to the
  362.          * _beginning_.
  363.          */
  364. {
  365.     register unsigned char sc;        // The source character:  the 8-bit character
  366.                                             // presently being converted.
  367.     register long count;
  368.     unsigned char *finalSP;
  369.     unsigned char *initialSP;
  370.     
  371.     
  372.         /*
  373.          * First, take everything past changeEnd and bump it up where
  374.          * it's supposed to go.
  375.          */
  376.     
  377.     BlockMove(*text - offset + changeEnd,
  378.         *text - offset + changeEnd + lengthIncrease,
  379.         textLen - offset - changeEnd);
  380.     
  381.     
  382.         /*
  383.          * In code segments, ThC won't let you have more than two address
  384.          * registers, even if you ask politely with sugar on top.  So
  385.          * I'm not going to bother asking, I'm just going to take them.
  386.          */
  387. #define checkP a0                // When srcP gets here, check to see if we're done.
  388. #define scratchPtr a0        // A scratch pointer.
  389. #define replPtr a1            // The pointer into the replacement array.
  390. #define doProgPtr a1            // The pointer to the "DoProgress" callback.
  391. #define srcP a2                // The source pointer:  this points to the 8-bit
  392.                                     // characters that get converted.
  393. #define destP a3                // The destination pointer:  this points to the
  394.                                     // 7-bit characters that have been converted.
  395.     
  396.     asm {
  397.             movem.l        a2-a3,-(a7)                    // save the two address regs we're not supposed to have!
  398.             move.l        (text), scratchPtr        // set up...
  399.             move.l        (scratchPtr), finalSP    // ...
  400.             move.l        offset, count                // ...
  401.             sub.l            count, finalSP                // ...
  402.             move.l        finalSP, srcP                // ...
  403.             add.l            changeEnd, srcP            // ...srcP...
  404.             move.l        srcP, destP                    // ...
  405.             move.l        srcP, initialSP            // ...initialSP...
  406.             add.l            lengthIncrease, destP    // ...destP...
  407.             move.l        destP, checkP                // ...checkP...
  408.             move.l        changeStart, count        // ...
  409.             add.l            count, finalSP                // ...and finalSP
  410.             clr.l            sc                                // clear the source char reg
  411.             bra.s            @updateCheckP                // make sure we won't go too far
  412.             
  413. @loop:    move.b        -(srcP), sc                    // load the source char reg
  414.             bmi.s            @char8                        // if hi bit set, it's an 8-bit char
  415.                                                             // otherwise it's a normal 7-bit char
  416. @char7:    move.b        sc, -(destP)                // just move it to the destination
  417.             cmpa.l        srcP, checkP                // do we need to do a checkup?
  418.             bne.s            @loop                            // if not, continue
  419.             bra.s            @doCheckup                    // if so, do it
  420.             
  421. @char8:    lea            replacement, replPtr        // put the addr of the array into replPtr
  422.             andi.b        #0x7F, sc                    // mask off the hi bit of the 8-bit char
  423.             add.b            sc, sc                        // index 4*sc bytes into...
  424.             adda.w        sc, replPtr                    // ...the array, since each entry...
  425.             adda.w        sc, replPtr                    // ...is four bytes long
  426.             moveq            #3, count                    // put a maximum of four bytes at destP
  427. @movRep:    move.b        (replPtr)+, -(destP)        // shove one byte
  428.             tst.b            (replPtr)                    // is it a null char?
  429.             dbeq            count, @movRep                // if so, or if we've done four bytes, stop
  430.             
  431. @test:    cmpa.l        srcP, checkP                // do we need to do a checkup?
  432.             bne.s            @loop                            // if not, continue
  433.                                                             // if so, do it
  434.             
  435. @doCheckup:
  436.             cmpa.l        finalSP, checkP            // are we totally done?
  437.             beq.s            @done                            // yup, quit
  438. @showProgress:                                            // nope, update progress thermometer
  439.             movem.l        d0-d1/a0-a1, -(a7)        // save registers we'll need later
  440.             move.l        callbacks, doProgPtr        // load the routine's address...
  441.             movea.l        OFFSET(ExternalCallbackBlock,DoProgress)(doProgPtr), doProgPtr
  442.             move.l        initialSP, count            // Calculate how far we've gone, assuming
  443.             add.l            count, count                // that resizeTextHndl() already took half
  444.             sub.l            srcP, count                    // the time.  (initialSP-finalSP) is the
  445.             sub.l            finalSP, count                // total distance, so ((2*initialSP) -
  446.             lsr.l            #1, count                    // finalSP - srcP)/2 is our progress.
  447.             clr.w            -(a7)                            // clear space for Boolean return
  448.             move.l        count, -(a7)                // push "done" parameter onto stack
  449.             jsr            (doProgPtr)                    // do the callback!
  450.             addq            #2, a7                        // ignore the result
  451.             movem.l        (a7)+, d0-d1/a0-a1        // restore those registers
  452.             
  453. @updateCheckP:
  454.             sub.l            #nPrgsBytes, checkP        // move checkP to the next checkup point
  455.             cmpa.l        finalSP, checkP            // is this the last leg of our journey?
  456.             bge.s            @test                            // if not, continue
  457.             movea.l        finalSP, checkP            // if so, make sure we don't go too far...
  458.             bra.s            @test                            // ...then continue
  459.             
  460. @done:    movem.l        (a7)+,a2-a3                    // restore those registers we "stole"
  461.     }
  462. }
  463.  
  464.  
  465.  
  466. /******************************/
  467.  
  468.  
  469.  
  470. pascal void main(ExternalCallbackBlock *callbacks, WindowPtr w)
  471. {
  472.     DialogPtr d;
  473.     short item;
  474.     GrafPtr save_port;
  475.     long selStart, selEnd, firstChar;
  476.     
  477.     short    act_len;
  478.     
  479.     OSErr err;
  480.     
  481.     RememberA0();
  482.     SetUpA4();
  483.     
  484.     callbacks->GetPreference('827 ', sizeof(options8To7), &options8To7, &act_len);
  485.     
  486.     if (act_len < 0)
  487.     {
  488.         options8To7.essetToSS = FALSE;
  489.         options8To7.euroquotesToInequalities = FALSE;
  490.         options8To7.convertDocument = FALSE;
  491.         options8To7.copyToClipboard = FALSE;
  492.     };
  493.     
  494.     GetPort(&save_port);
  495.     d = callbacks->CenterDialog(128);
  496.     SetPort(d);
  497.     
  498.     SetupUserItem(d, k_line, callbacks->FrameDialogItem);
  499.     
  500.     callbacks->GetSelection(&selStart, &selEnd, &firstChar);
  501.     nonEmptySelection = (selEnd > selStart);
  502.     
  503.     do
  504.     {
  505.         maintain_buttons(d);
  506.         
  507.         ModalDialog(callbacks->StandardFilter, &item);
  508.         
  509.         switch (item)
  510.         {
  511.             case k_essetToB:                options8To7.essetToSS = FALSE;                break;
  512.             case k_essetToSS:                options8To7.essetToSS = TRUE;                    break;
  513.                 
  514.             case k_euroquotesToQuotes:            options8To7.euroquotesToInequalities = FALSE;    break;
  515.             case k_euroquotesToInequalities:    options8To7.euroquotesToInequalities = TRUE;        break;
  516.                 
  517.             case k_bulletToStar:            options8To7.bulletToO = FALSE;                break;
  518.             case k_bulletToO:                options8To7.bulletToO = TRUE;                    break;
  519.                 
  520.             case k_convertSelection:    options8To7.convertDocument = FALSE;        break;
  521.             case k_convertDocument:        options8To7.convertDocument = TRUE;            break;
  522.                 
  523.             case k_changeInPlace:        options8To7.copyToClipboard = FALSE;        break;
  524.             case k_copyToClipboard:        options8To7.copyToClipboard = TRUE;            break;
  525.         }
  526.     } while ((item != ok) && (item != cancel));
  527.     
  528.     DisposDialog(d);
  529.     SetPort(save_port);
  530.     
  531.     if (item == ok)
  532.     {
  533.         Handle h, text;
  534.         long textLen;
  535.         long lengthIncrease;
  536.         long changeStart, changeEnd;
  537.         long offset;
  538.         long extendLengthBy;
  539.         
  540.         callbacks->SetPreference('827 ', sizeof(options8To7), &options8To7, &act_len);
  541.         
  542.         h = callbacks->GetWindowContents(w);
  543.         textLen = GetHandleSize(h);
  544.         
  545.         if (options8To7.convertDocument) {
  546.             changeStart = 0;                changeEnd = textLen;
  547.         } else {
  548.             changeStart = selStart;        changeEnd = selEnd;
  549.         }
  550.         
  551.         if (options8To7.copyToClipboard) {
  552.             text = callbacks->Allocate(changeEnd-changeStart, FALSE);
  553.             if (text == NULL) {
  554.                 callbacks->ReportOSError(memFullErr);
  555.                 goto done8To7;
  556.             }
  557.             BlockMove(*h + changeStart, *text, changeEnd-changeStart);
  558.             offset = changeStart;
  559.         } else {
  560.             text = h;
  561.             offset = 0;
  562.         }
  563.         
  564.         updateReplacementArray();
  565.         
  566.         
  567.         callbacks->StartProgress("\pConverting…",        // string to display
  568.             changeEnd-changeStart,                            // total distance to go
  569.             FALSE);                                                // can't cancel
  570.         
  571.         lengthIncrease = resizeTextHndl(callbacks,
  572.             text, offset, changeStart, changeEnd,
  573.             &selStart, &selEnd);
  574.         if (lengthIncrease < 0) {
  575.             callbacks->DoneProgress();
  576.             callbacks->ReportOSError(memFullErr);
  577.             goto done8To7;
  578.         }
  579.         
  580.             /*
  581.              * Here's where all the real work gets done!
  582.              */
  583.         replaceText(callbacks,
  584.             text, offset, changeStart, changeEnd,
  585.             textLen, lengthIncrease);
  586.         
  587.         callbacks->DoneProgress();
  588.         
  589.         
  590.         if (options8To7.copyToClipboard) {
  591.             HLock(text);
  592.             ZeroScrap();
  593.             PutScrap(changeEnd - changeStart + lengthIncrease, 'TEXT', *text);
  594.             DisposHandle(text);
  595.         } else {
  596.             callbacks->ContentsChanged(w);
  597.             callbacks->SetSelection(selStart, selEnd, firstChar);
  598.         }
  599.     }
  600.     
  601. done8To7:
  602.     RestoreA4();
  603. }
  604.  
  605.